﻿using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Windows.Forms;
using AndBurn.DDSReader;
using DnPakExplorer.Forms;
using Vlc.DotNet.Core.Interops;
using Vlc.DotNet.Core;
using Vlc.DotNet.Forms;
using System.Runtime.InteropServices;
using System.Xml;
using ZLibNet;
using DnPakExplorer.Controls;

namespace DnPakExplorer {
	public partial class PakExplorer : FormBase {

		const int ICON_INDEX_FONT = 0;
		const int ICON_INDEX_DNT = 1;
		const int ICON_INDEX_ERROR = 2;
		const int ICON_INDEX_LUO = 3;
		const int ICON_INDEX_FOLDER = 8;
		const int ICON_INDEX_FOLDER_CLOSED = 16;
		const int ICON_INDEX_TEXT = 5;

		VideoForm mVideoForm;

		ProgressForm mProgress;
		EquipmentStoreViewerForm mStoreForm;

		//#region
		//[StructLayout(LayoutKind.Sequential)]
		//public struct MARGINS {
		//	public int Left;
		//	public int Right;
		//	public int Top;
		//	public int Bottom;
		//}

		//[DllImport("dwmapi.dll", PreserveSig = false)]
		//public static extern void DwmExtendFrameIntoClientArea
		//(IntPtr hwnd, ref MARGINS margins);

		//[DllImport("dwmapi.dll", PreserveSig = false)]
		//public static extern bool DwmIsCompositionEnabled();

		//protected override void OnLoad(EventArgs e) {
		//	if (DwmIsCompositionEnabled()) {
		//		MARGINS margin = new MARGINS();
		//		margin.Right = margin.Left = margin.Bottom = margin.Top = -1;
		//		DwmExtendFrameIntoClientArea(this.Handle, ref margin);
		//	}
		//	base.OnLoad(e);
		//}

		//protected override void OnPaintBackground(PaintEventArgs e) {
		//	base.OnPaintBackground(e);
		//	if (DwmIsCompositionEnabled()) {
		//		e.Graphics.Clear(Color.Black);
		//	}
		//}



		//#endregion

		public PakExplorer() {
			InitializeComponent();
			Util.SetExplorer(this);
			treeView1.ShowNodeToolTips = true;
			SetStyle(ControlStyles.ResizeRedraw, true);
			menuStrip1.Renderer = new DnPakExplorer.Controls.ContextMenuStripRenderer();
		}


		void CreatePakFile(string dest, string from) {
			ProgressForm progress = new ProgressForm();
			progress.Text = "创建Pak文件";
			progress.label2.Text = "";
			new Thread(delegate() {
				List<FileHeader> headers = new List<FileHeader>();
				progress.InvokeIfRequired(l => l.label1.Text = "收集文件。。。");
				CreateFileHeaderFromDisk(from, headers);
				progress.InvokeIfRequired(l => l.label1.Text = "写入数据。。。");
				int parentPathLen = from.Length;
				if (dest.EndsWith(Path.DirectorySeparatorChar+""))
					parentPathLen--;
				using (FileStream fileOut = new FileStream(dest, FileMode.Create)) {
					BinaryWriter rt = new BinaryWriter(fileOut);
					byte[] fileId = ASCIIEncoding.ASCII.GetBytes("EyedentityGames Packing File 0.1");
					fileOut.Write(fileId, 0, fileId.Length);
					fileOut.Seek(256, SeekOrigin.Begin);	// file decription
					rt.Write(0x0b);					// versionID
					rt.Write(headers.Count);				// recordCound
					rt.Write(0);							// firstRecordHeadOffset, write later
					rt.Seek(756, SeekOrigin.Current);

					rt.Seek(0x400, SeekOrigin.Begin);
					rt.Write((byte)0x78);
					rt.Write((byte)0x01);

					byte[] buff = new byte[10240];
					int read = 0;
					int count = 0;
					foreach (FileHeader f in headers) {
						int size = 0;
						f.pakOffset = (int)rt.BaseStream.Position;
						using (FileStream fileIn = File.OpenRead(f.fileName)) {
							f.realSize = (int)fileIn.Length;
							ZLibStream z = new ZLibStream(fileOut, ZLibNet.CompressionMode.Compress, true);
							while ((read = fileIn.Read(buff, 0, buff.Length))>0) {
								z.Write(buff, 0, read);
								size += read;
							}
							z.Close();
						}
						f.packedSize = size;
						f.sizeInPak = size;
						f.flag = 0;
						count++;
						progress.InvokeIfRequired(l => {
							l.label2.Text = count*100/headers.Count+"%";
							l.progressBar1.Value = count*l.progressBar1.Maximum/headers.Count;
						});
					}
					progress.InvokeIfRequired(l => l.label1.Text = "写入文件列表。。。");
					int firstRecordHeadOffset = (int)rt.BaseStream.Position;
					foreach (FileHeader f in headers) {
						byte[] fileNameBuff = ASCIIEncoding.ASCII.GetBytes(f.fileName.Substring(parentPathLen));
						int nameLen = fileNameBuff.Length;
						rt.Write(fileNameBuff, 0, nameLen);
						rt.Seek(256-nameLen, SeekOrigin.Current);
						rt.Write(f.packedSize);
						rt.Write(f.realSize);
						rt.Write(f.sizeInPak);
						rt.Write(f.pakOffset);
						rt.Write(f.flag);
						rt.Seek(40, SeekOrigin.Current);
					}

					rt.Seek(264, SeekOrigin.Begin);
					rt.Write(firstRecordHeadOffset);
				}
				progress.InvokeIfRequired(l => l.Close());
			}).Start();
			progress.ShowDialog();
		}

		private void CreateFileHeaderFromDisk(string path, List<FileHeader> headers) {
			string[] files = Directory.GetFiles(path);
			foreach (string f in files) {
				FileHeader fh = new FileHeader();
				fh.fileName = f;
				headers.Add(fh);
			}
			string[] dirs = Directory.GetDirectories(path);
			foreach (string d in dirs) {
				CreateFileHeaderFromDisk(d, headers);
			}
		}


		void ReadPak(string filename, List<FileHeader> headers) {
			FileStream file = new FileStream(filename, FileMode.Open);
			BinaryReader br = new BinaryReader(new BufferedStream(file));

			byte[] fileID = br.ReadBytes(256);
			int ver = br.ReadInt32();
			int recordCount = br.ReadInt32();
			int firstRecordHeadOffset = br.ReadInt32();
			byte[] reserved = br.ReadBytes(756);

			br.BaseStream.Seek(firstRecordHeadOffset, SeekOrigin.Begin);
			byte[] buff = new byte[256];
			int fileCount = 0;
			for (int i=0; i<recordCount; i++) {
				FileHeader header = new FileHeader();
				br.Read(buff, 0, 256);
				int len;
				for (len=0; len<256; len++)
					if (buff[len]==0)
						break;
				header.fileName = System.Text.Encoding.Default.GetString(buff, 0, len);
				header.packedSize = br.ReadInt32();
				header.realSize = br.ReadInt32();
				header.sizeInPak = br.ReadInt32();
				header.pakOffset = br.ReadInt32();
				header.flag = br.ReadInt32();
				header.reserved = br.ReadBytes(40);
				header.pakFilePath = filename;
				if (header.fileName == "") {
					// TODO
					Console.Write("Warning: empty filename inf pak file("+header.pakFilePath+") founded");
					header.fileName = "Empty named file.unkown";
				}
				//if(header.fileName.EndsWith(".mDnt"))
				headers.Add(header);
				fileCount++;
				if (fileCount%100==0) {
					//Thread.Sleep(10);
					//Application.DoEvents();
				}
			}
			curCount++;
			total += fileCount;
			progress = (double)curCount/pakCount;
			br.Close();
			file.Close();

		}

		double progress = 0;
		int curCount = 0;
		int pakCount = 0;
		int step = 0;
		int added = 0;
		int total = 0;

		private void OnLoad(object sender, EventArgs e) {
			if (MessageBox.Show("是否导入龙之谷资源包？", "提示", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK) {
				LoadDnResources();
			} else {
                string[] files = Directory.GetFiles(".\\Resources", "*.pak");
				List<FileHeader> headers = new List<FileHeader>(1000);
				foreach (string path in files) {
					ReadPak(path, headers);
				}
				if (headers.Count>0)
					Add(treeView1.Nodes.Add("Files").Nodes, 1, headers);
			}
			LoadData(".\\Data\\Data.xml");
		}

		private void LoadDnResources() {
			PakFileSelectForm form = new PakFileSelectForm();
			if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
				Thread thead = new Thread(delegate() {
					mProgress = new ProgressForm();
					mProgress.StartPosition = FormStartPosition.CenterScreen;
					mProgress.Show();
					while (step<2) {
						if (step == 0) {
							mProgress.InvokeIfRequired(l => {
								l.label2.Text = (int)(progress*100)+"%";
								l.progressBar1.Value=(int)(progress*l.progressBar1.Maximum);
							});
						} else
							mProgress.InvokeIfRequired(l => {
								l.label2.Text = (int)(added*100/total)+"%";
								l.progressBar1.Value=(int)(added*l.progressBar1.Maximum/total);
							});
						mProgress.InvokeIfRequired(l => l.label1.Text = step==0?"读取数据。。。":"处理数据。。。");
						Application.DoEvents();
						System.Threading.Thread.Sleep(10);
					}
					mProgress.Close();
				});
				thead.Start();

				string[] paths = form.SelectedFiles;
				pakCount = paths.Length;
				curCount = 0;
				progress = 0;
				added = 0;
				total = 0;
				step = 0;
				List<FileHeader> headers = new List<FileHeader>(1000);
				foreach (string path in paths) {
					ReadPak(path, headers);
				}
				step = 1;
				TreeNode filesNode = new TreeNode("Files");
				filesNode.ImageIndex = ICON_INDEX_FOLDER_CLOSED;
				Add(filesNode.Nodes, 1, headers);
				// 先构建子树再添加到视图中会极大提升速度
				treeView1.Nodes.Add(filesNode);
				step = 2;
			}
		}

		private void LoadData(string filepath) {
			XmlDocument doc = new XmlDocument();
			doc.Load(filepath);
			XmlNodeList entryNodeList = doc.SelectNodes("/Root/PakFile/CommonPakEntries/Entry");
			TreeNode entries = treeView1.Nodes.Add("Entries");
			TreeNode root = FindSingleTreeNodeByText(treeView1.Nodes, "Files");
			foreach (XmlNode entryNode in entryNodeList) {
				TreeNode entry = entries.Nodes.Add(entryNode.Attributes.GetNamedItem("name").InnerText);
				entry.Tag = entryNode.Attributes.GetNamedItem("path").InnerText;
				entry.ImageIndex = GetFileIconInde("dnt");
				entry.SelectedImageIndex = GetFileIconInde("dnt");
				entry.ToolTipText = (string)entry.Tag;

				if (root != null) {
					//TreeNode targetNode = FindTreeNodeWithPath((string)entry.Tag, root);
					//if (targetNode != null) {
					//	targetNode.ToolTipText = entry.Text;
					//	targetNode.BackColor = Color.LightGray;
					//}
				}
			}
		}

		private void Add(TreeNodeCollection parent, int offset, List<FileHeader> headers) {
			Hashtable directories = new Hashtable();
			List<FileHeader> files = new List<FileHeader>();
			for (int i=0; i<headers.Count; i++) {
				int index = headers[i].fileName.IndexOf('\\', offset);
				if (index >= 0) {
					string name = headers[i].fileName.Substring(offset, index-offset);
					List<FileHeader> list = directories[name] as List<FileHeader>;
					if (list == null) {
						list = new List<FileHeader>();
						directories.Add(name, list);
					}
					list.Add(headers[i]);
				} else {
					files.Add(headers[i]);
				}
			}
			files.Sort();
			//TreeNode[] fileNodes = new TreeNode[files.Count];
			//for (int row=0; row<fileNodes.Length; row++) {
			//	fileNodes[row] = new TreeNode(files[row].fileName);
			//	fileNodes[row].Tag = files[row];
			//	fileNodes[row].ImageIndex = GetFileIconInde(files[row].fileName);
			//	added++;
			//}
			//parent.AddRange(fileNodes);
			foreach (FileHeader header in files) {
				TreeNode node = parent.Add(header.fileName.Substring(offset));
				node.Tag = header;
				node.ImageIndex = GetFileIconInde(header.fileName);
				added++;
			}
			DictionaryEntry[] arr = new DictionaryEntry[directories.Count];
			var items = directories.Values;
			var keys = directories.Keys;
			directories.CopyTo(arr, 0);
			Array.Sort(arr, new a());
			foreach (DictionaryEntry entry in arr) {
				TreeNode node = parent.Add(entry.Key.ToString());
				node.ImageIndex = ICON_INDEX_FOLDER_CLOSED;
				Add(node.Nodes, offset+entry.Key.ToString().Length+1, (List<FileHeader>)entry.Value);
			}
		}

		class a : IComparer {
			public int Compare(object x, object y) {
				return ((string)((DictionaryEntry)x).Key).CompareTo((string)((DictionaryEntry)y).Key);
			}
		}

		private int GetFileIconInde(string filename) {
			switch (Path.GetExtension(filename).ToLower()) {
			case ".dnt":
				return 18;
			case ".dds":
				return 12;
			case ".font":
				return 9;
			case ".lua":
				return 6;
			case ".xml":
				return 19;
			case ".avi":
				return 17;
			case ".ogg":
			case ".wav":
			case ".mp3":
				return 20;
			case ".msh":
				return 21;
			case ".eff":
				return 22;
			case ".jpg":
			case ".png":
			case ".gif":
				return 10;
			default:
				return 15;
			}
		}

		private void OnMenuOpen(object sender, EventArgs e) {
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.Filter = "*dnt|*.dnt|*.pak|*.pak";
			dlg.CheckFileExists = true;
			dlg.Multiselect = false;
			if (dlg.ShowDialog() == DialogResult.OK) {
				if (dlg.FileName.EndsWith(".dnt", StringComparison.OrdinalIgnoreCase)) {
					DntExplorer dnt = new DntExplorer();
					dnt.LoadDnt(dlg.FileName);
					dnt.Show();
				} else if (dlg.FileName.EndsWith(".pak", StringComparison.OrdinalIgnoreCase)) {
					OpenPakFile(dlg.FileName);
				}
			}
		}

		private void OpenPakFile(string path) {
			List<FileHeader> headers = new List<FileHeader>(1000);
			ReadPak(path, headers);
			Add(treeView1.Nodes.Add("Files").Nodes, 1, headers);
		}

		private void ExtractTo(FileHeader fh, string path) {
			using (FileStream ofs = new FileStream(path, FileMode.Create)) {
				using (Stream ins = GetFileStream(fh)) {
					byte[] buffer = new byte[10240];
					int lenRead = 0;
					while ((lenRead=ins.Read(buffer, 0, buffer.Length)) > 0) {
						ofs.Write(buffer, 0, lenRead);
					}
				}
			}
		}

		private void ExtractAllTo(List<FileHeader> list, string path) {
			int i = 0;
			foreach (FileHeader fh in list) {
				FileInfo file = null;
				if (fh.fileName.StartsWith(Path.DirectorySeparatorChar+""))
					file = new FileInfo(Path.Combine(path, fh.fileName.Substring(1)));
				else
					file = new FileInfo(Path.Combine(path, fh.fileName));
				if (!file.Directory.Exists) {
					Directory.CreateDirectory(file.Directory.FullName);
				}
				ExtractTo(fh, file.FullName);
				i++;
				if (mProgress != null) {
					mProgress.InvokeIfRequired(l => {
						l.label2.Text = i*100/list.Count+"%";
						l.progressBar1.Value = i*l.progressBar1.Maximum/list.Count;
					});
				}
			}
			if (mProgress != null) {
				mProgress.InvokeIfRequired(l => mProgress.Close());
			}
		}

		private void OnContextMenu(object sender, EventArgs e) {
			ToolStripItem item = (ToolStripItem)sender;
			if (item.Text == "提取") {
				TreeNode node = item.Tag as TreeNode;
				FileHeader header = node.Tag as FileHeader;

				SaveFileDialog dlg = new SaveFileDialog();
				dlg.FileName = Path.GetFileName(header.fileName);
				string ext = "*"+Path.GetExtension(dlg.FileName).ToLower();
				if (ext.Equals("*.dds", StringComparison.OrdinalIgnoreCase)) {
					dlg.Filter = "*.bmp|*.bmp|*.dds|*.dds|*.emf|*.emf|*.exif|*.exif|*.gif|*.gif|*.ico|*.ico|*.jpg|*.jpg|*.png|*.png|*.tiff|*.tiff|*.wmf|*.wmf";
				} else {
					dlg.Filter = ext+"|"+ext;
				}

				if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
					return;

				string targetExt = "*"+Path.GetExtension(dlg.FileName).ToLower();
				if (targetExt == ext) {
					ExtractTo(header, dlg.FileName);
				} else if (ext == "*.dds") {
					ImageFormat imageFormat = null;
					switch (targetExt) {
					case "*.bmp":
						imageFormat = ImageFormat.Bmp;
						break;
					case "*.emf":
						imageFormat = ImageFormat.Emf;
						break;
					case "*.exif":
						imageFormat = ImageFormat.Exif;
						break;
					case "*.gif":
						imageFormat = ImageFormat.Gif;
						break;
					case "*.icon":
						imageFormat = ImageFormat.Icon;
						break;
					case "*.jpeg":
						imageFormat = ImageFormat.Jpeg;
						break;
					case "*.png":
						imageFormat = ImageFormat.Png;
						break;
					case "*.tiff":
						imageFormat = ImageFormat.Tiff;
						break;
					case "*.wmf":
						imageFormat = ImageFormat.Wmf;
						break;
					default:
						MessageBox.Show("不支持的文件格式");
						break;
					}

					if (imageFormat!= null) {
						using (Stream ins = GetFileStream(header)) {
							DDSImage dds = new DDSImage(ins);
							dds.BitmapImage.Save(dlg.FileName, imageFormat);
						}
					}
				}


			} else if (item.Text == "属性") {
				TreeNode node = item.Tag as TreeNode;
				FileHeader header = node.Tag as FileHeader;
				if (header != null) {
					WebMessage msg = new WebMessage();
					msg.Text = "属性";
					msg.SetHtmlString(new StringBuilder()
						.Append(@"<html><body style=""font:normal 12px/24px Helvetica, Tahoma, Arial, sans-serif""><li>文件名:").Append(header.fileName)
						.Append("<il><li>压缩大小:").Append(header.packedSize)
						.Append("<il><li>实际大小:").Append(header.realSize)
						.Append("<il><li>包内大小:").Append(header.sizeInPak)
						.Append("<il><li>包内偏移:").Append(header.pakOffset)
						.Append("<il><li>标志:").Append(header.flag)
						.Append("<il><li>所属PAK文件:").Append(header.pakFilePath)
						.Append("<il></body></html>").ToString());
					msg.Size = new Size(500, 260);

					msg.StartPosition = FormStartPosition.CenterParent;
					msg.Show();
				}
			} else if (item.Text == "复制名称") {
				TreeNode node = item.Tag as TreeNode;
				FileHeader header = node.Tag as FileHeader;
				Clipboard.SetDataObject(Path.GetFileName(header.fileName), true);
			} else if (item.Text == "复制路径") {
				TreeNode node = item.Tag as TreeNode;
				FileHeader header = node.Tag as FileHeader;
				Clipboard.SetDataObject(header.fileName, true);
			} else if (item.Text == "提取所有") {
				FolderBrowserDialog dlg = new FolderBrowserDialog();
				dlg.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
				if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
					TreeNode node = item.Tag as TreeNode;
					mProgress = new ProgressForm();
					mProgress.StartPosition = FormStartPosition.CenterScreen;
					mProgress.Text = "解压文件";
					mProgress.label1.Text = "正在解压文件。。。";
					Thread thead = new Thread(delegate() {
						List<FileHeader> list = new List<FileHeader>();
						GetAllFileHeader(node, list);
						ExtractAllTo(list, dlg.SelectedPath);
					});
					thead.Start();
					mProgress.ShowDialog();
				}
			}
		}

		private void GetAllFileHeader(TreeNode parent, List<FileHeader> list) {
			foreach (TreeNode node in parent.Nodes) {
				if (node.Nodes.Count == 0) {
					FileHeader header = node.Tag as FileHeader;
					if (header != null)
						list.Add(header);
				} else {
					GetAllFileHeader(node, list);
				}
			}
		}

		private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) {
			if (e.Button == MouseButtons.Right) {
				ContextMenuStrip menu = new ContextMenuStrip();
				menu.Renderer = new ContextMenuStripRenderer();
				if (e.Node.Nodes.Count==0)
					menu.Items.Add("提取", null, OnContextMenu).Tag = e.Node;
				else
					menu.Items.Add("提取所有", null, OnContextMenu).Tag = e.Node;
				menu.Items.Add("属性", null, OnContextMenu).Tag = e.Node;
				menu.Items.Add("复制名称", null, OnContextMenu).Tag = e.Node;
				menu.Items.Add("复制路径", null, OnContextMenu).Tag = e.Node;
				menu.Show(Cursor.Position);
			}
		}

		private void OnMenuEquip(object sender, EventArgs e) {
			Character ch = DnPlayerUtil.CurrentCharacter = DnPlayerUtil.SelectOrCreateICharacter;
			if (ch != null) {
				new Equiper(ch).Show();
			}
			
		}

		public Stream GetFileStream(FileHeader header) {
			FileStream fs = new FileStream(header.pakFilePath, FileMode.Open);
			fs.Seek(header.pakOffset, SeekOrigin.Begin);
			ZLibStream z = new ZLibStream(fs, ZLibNet.CompressionMode.Decompress);
			return new BufferedStream(z);
		}

		public Stream GetRawFileStream(FileHeader header) {
			FileStream fs = new FileStream(header.pakFilePath, FileMode.Open);
			fs.Seek(header.pakOffset, SeekOrigin.Begin);
			return new BufferedStream(fs);
		}

		private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) {
			if (e.Node.Nodes.Count == 0) {
				FileHeader header = e.Node.Tag as FileHeader;
				if (header != null) {
					OpenFile(header);
				}
				string path = e.Node.Tag as string;
				if (path != null) {
					FileHeader fh = FindFileHeaderWithPath(path);
					if (fh != null) {
						OpenFile(fh);
					}
				}
			}
		}

		private void OpenFile(FileHeader header) {
			if (header.fileName.EndsWith(".dnt", StringComparison.OrdinalIgnoreCase)) {
				DntExplorer dnt = new DntExplorer();
				dnt.LoadDnt(header, Path.GetFileName(header.fileName));
				dnt.StartPosition = FormStartPosition.CenterScreen;
				dnt.Show();
			}

			if (header.fileName.EndsWith(".dds", StringComparison.OrdinalIgnoreCase)) {
				using (Stream s = GetFileStream(header)) {
					DDSForm dds = new DDSForm();
					dds.Text = Path.GetFileName(header.fileName);
					dds.LoadDDS(s);
					dds.StartPosition = FormStartPosition.CenterScreen;
					dds.Show();
				}
			}
			if (header.fileName.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)
				|| header.fileName.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)
				|| header.fileName.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) {
				using (Stream s = GetFileStream(header)) {
					DDSForm dds = new DDSForm();
					dds.Text = Path.GetFileName(header.fileName);
					dds.StartPosition = FormStartPosition.CenterScreen;
					dds.SetImage(new Bitmap(s));
					dds.Show();
				}
			}

			if (header.fileName.EndsWith(".wav", StringComparison.OrdinalIgnoreCase)
				|| header.fileName.EndsWith(".ogg", StringComparison.OrdinalIgnoreCase)
				) {
				FileInfo file = new FileInfo(Environment.CurrentDirectory+"\\tmp"+header.fileName);
				if (!file.Directory.Exists)
					file.Directory.Create();
				if (!file.Exists) {
					ExtractTo(header, file.FullName);
				}
				if (mVideoForm == null || mVideoForm.IsDisposed) {
					mVideoForm = new VideoForm();
					mVideoForm.StartPosition = FormStartPosition.CenterScreen;
				}
				mVideoForm.Show();
				mVideoForm.SetFile(file);
			}
		}

		public TreeNode FindSingleTreeNodeByText(TreeNodeCollection collection, string text) {
			foreach (TreeNode node in collection) {
				if (node.Text == text) {
					return node;
				}
			}
			return null;
		}

		public FileHeader FindFileHeaderWithPath(string path) {
			TreeNode root = FindSingleTreeNodeByText(treeView1.Nodes, "Files");
			if (root == null)
				return null;
			root = FindTreeNodeWithPath(path, root);
			if (root != null) {
				return root.Tag as FileHeader;
			}
			return null;
		}

		private TreeNode FindTreeNodeWithPath(string path, TreeNode parent) {
			string[] paths = path.Split('\\');
			if (paths.Length <= 0) {
				return null;
			}
			int index = 0;
			if (paths[index] == "")
				index++;
			return FindTreeNodeWithPath(paths, index, parent);
		}


		private TreeNode FindTreeNodeWithPath(string[] paths, int index, TreeNode parent) {
			foreach (TreeNode node in parent.Nodes) {
				if (node.Text == paths[index]) {
					if (index >= paths.Length-1) {
						return node;
					} else {
						return FindTreeNodeWithPath(paths, index+1, node);
					}
				}
			}
			return null;
		}


		private void OnMenuLoadDnResources(object sender, EventArgs e) {
			LoadDnResources();
		}

		private void treeView1_AfterExpand(object sender, TreeViewEventArgs e) {
			e.Node.ImageIndex = ICON_INDEX_FOLDER;
			if (e.Node.IsSelected) {
				e.Node.SelectedImageIndex = e.Node.ImageIndex;
			}
		}

		private void treeView1_AfterCollapse(object sender, TreeViewEventArgs e) {
			e.Node.ImageIndex = ICON_INDEX_FOLDER_CLOSED;
			if (e.Node.IsSelected) {
				e.Node.SelectedImageIndex = e.Node.ImageIndex;
			}
		}

		private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) {
			e.Node.SelectedImageIndex = e.Node.ImageIndex;
		}

		private void treeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e) {
			//e.Node.SelectedImageIndex = e.Node.ImageIndex;
		}

		private void DnPakExplorer_FormClosed(object sender, FormClosedEventArgs e) {
			treeView1.Nodes.Clear();
		}

		private void TestOne(object sender, EventArgs e) {
			new VideoForm().Show();
		}

		private void TestTwo(object sender, EventArgs e) {
			new Vlc.DotNet.Forms.Samples.Sample().Show();
		}

		private void OnMenuPakMaker(object sender, EventArgs e) {
			FolderBrowserDialog dlg = new FolderBrowserDialog();
			dlg.Description = "选择要打包的文件目录";
			if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
				SaveFileDialog saveDlg = new SaveFileDialog();
				saveDlg.OverwritePrompt = true;
				saveDlg.DefaultExt = ".pak";
				if (saveDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
					CreatePakFile(saveDlg.FileName, dlg.SelectedPath);
				}
			}
		}

		private void OnMenuDeleteTemp(object sender, EventArgs e) {
			if (new DirectoryInfo(Environment.CurrentDirectory+"\\tmp").Exists)
				Directory.Delete(Environment.CurrentDirectory+"\\tmp", true);
		}

		private void OnMenuStore(object sender, EventArgs e) {
			if (mStoreForm == null || mStoreForm.IsDisposed) {
				mStoreForm = new EquipmentStoreViewerForm(this);
				mStoreForm.StartPosition = FormStartPosition.CenterScreen;
				mStoreForm.Show();
			}
		}

		public void GetFileHeaders(string dirPath, List<FileHeader> list) {
			TreeNode extNode = FindTreeNodeWithPath(@"\resource\ext", FindSingleTreeNodeByText(treeView1.Nodes, "Files"));
			foreach (TreeNode node in extNode.Nodes) {
				FileHeader fh = node.Tag as FileHeader;
				if (fh != null)
					list.Add(fh);
			}
		}

		private void dntableFindWidthFieldNameToolStripMenuItem_Click(object sender, EventArgs e) {
			InputForm inputForm = new InputForm();
			inputForm.label4.Text = "输入用于查找的属性名：";
			inputForm.label1.Text = "属性名";
			if (inputForm.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
				string str = inputForm.textBox1.Text;
				string result = "Search for Field:"+str+"\n";
				TreeNode extNode = FindTreeNodeWithPath(@"\resource\ext", FindSingleTreeNodeByText(treeView1.Nodes, "Files"));
				foreach (TreeNode node in extNode.Nodes) {
					FileHeader fh = node.Tag as FileHeader;

					if (fh != null) {
						using (Stream s = GetFileStream(fh)) {
							DntField[] fields = Dntable.LoadFields(s);
							int c = 0;
							foreach (DntField f in fields) {
								if (f.name.IndexOf(str, StringComparison.OrdinalIgnoreCase) >= 0) {
									result += fh.fileName+" field="+c+"\n";
									break;
								}
								c++;
							}
						}
					}

				}
				Clipboard.SetDataObject(result, true);
				MessageBox.Show(result);
			}
		}

		void Search(Stream stream, object value, DntFieldType type, out int foundKey, out int foundRow, out int foundField) {
			BinaryReader br = new BinaryReader(stream);
			br.ReadInt32();
			int fieldCount = br.ReadInt16();
			int recourdCount = br.ReadInt32();
			byte[] buff = new byte[256];
			DntField[] fields  = new DntField[fieldCount];
			for (int i=0; i<fieldCount; i++) {
				fields[i] = new DntField();
				short nameLen = br.ReadInt16();
				br.Read(buff, 0, nameLen);
				fields[i].name = System.Text.Encoding.Default.GetString(buff, 0, nameLen);
				fields[i].type = (DntFieldType)br.ReadByte();
			}

			foundKey = -1;
			foundRow = -1;
			foundField = -1;
			for (int r=0; r<recourdCount; r++) {
				int key = br.ReadInt32();
				for (int c=0; c<fieldCount; c++) {
					switch (fields[c].type) {
					case DntFieldType.Bool32:
						bool b = br.ReadInt32()!=0;
						if (type == DntFieldType.Bool32) {
							if (b == (bool)value) {
								foundKey = key;
								foundField = c;
								foundRow = r;
								br.Close();
								return;
							}
						}
						break;

					case DntFieldType.Float:
						float f = br.ReadSingle();
						if (type == DntFieldType.Float) {
							if (f == (float)value) {
								foundKey = key;
								foundField = c;
								foundRow = r;
								br.Close();
								return;
							}
						}
						break;

					case DntFieldType.FloatPer:
						float fp = br.ReadSingle();
						if (type == DntFieldType.Float) {
							if (fp == (float)value) {
								foundKey = key;
								foundField = c;
								foundRow = r;
								br.Close();
								return;
							}
						}
						break;

					case DntFieldType.Int32:
						int inte = br.ReadInt32();
						if (type == DntFieldType.Int32) {
							if (inte == (int)value) {
								foundKey = key;
								foundField = c;
								foundRow = r;
								br.Close();
								return;
							}
						}
						break;

					case DntFieldType.String:
						short stringLen = br.ReadInt16();
						if (stringLen>buff.Length)
							buff = new byte[stringLen];
						if (type == DntFieldType.String) {
							br.Read(buff, 0, stringLen);
							string s = System.Text.Encoding.Default.GetString(buff, 0, stringLen);
							if (s == (string)value) {
								foundKey = key;
								foundField = c;
								foundRow = r;
								br.Close();
								return;
							}
						} else {
							br.Read(buff, 0, stringLen);
						}
						break;

					}
				}
				if (type == DntFieldType.Int32 && key == (int)value) {
					foundKey = key;
					foundField = -1;
					foundRow = r;
					br.Close();
					return;
				}
			}

			br.Close();
		}

		private void searchDntWidthWalueToolStripMenuItem_Click(object sender, EventArgs e) {
			string result = "";
			InputForm inputForm = new InputForm();
			inputForm.label4.Text = "输入用于查找的数值：";
			inputForm.label1.Text = "数值";
			inputForm.textBox1.Text = "872416163";
			inputForm.comboBox1.Items.Add(DntFieldType.Int32);
			inputForm.comboBox1.Items.Add(DntFieldType.Float);
			inputForm.comboBox1.Items.Add(DntFieldType.String);
			inputForm.comboBox1.SelectedIndex = 0;
			if (inputForm.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
				DntFieldType type;
				object value = null;
				switch (inputForm.comboBox1.SelectedIndex) {
				case 0:

					value = int.Parse(inputForm.textBox1.Text);
					type = DntFieldType.Int32;
					break;
				case 1:
					value = float.Parse(inputForm.textBox1.Text);
					type = DntFieldType.Float;
					break;
				case 2:
					value = inputForm.textBox1.Text;
					type = DntFieldType.String;
					break;
				default:
					return;
				}
				result += "Search:type="+type+", value"+value+"\n";
				ProgressForm2 progress = new ProgressForm2();
				new Thread(delegate() {
					string str = inputForm.textBox1.Text;
					TreeNode extNode = FindTreeNodeWithPath(@"\resource\ext", FindSingleTreeNodeByText(treeView1.Nodes, "Files"));
					foreach (TreeNode node in extNode.Nodes) {
						FileHeader fh = node.Tag as FileHeader;
						if (fh != null) {
							progress.label2.InvokeIfRequired(l => l.Text=fh.fileName);
							using (Stream s = GetFileStream(fh)) {
								int foundKey = -1;
								int foundRow = -1;
								int foundField = -1;
								Search(s, value, type, out foundKey, out foundRow, out foundField);
								if (foundRow >= 0) {
									result += Path.GetFileName(fh.fileName)+":key="+foundKey+", Row="+foundRow+", Field="+foundField+"\n";
								}
							}
						}
					}
					progress.InvokeIfRequired(l => l.Close());
				}

				).Start();

				progress.StartPosition = FormStartPosition.CenterScreen;
				progress.ShowDialog();
				Clipboard.SetDataObject(result, true);
				MessageBox.Show(result);
			}
		}

		private void testLayerdWindowToolStripMenuItem_Click(object sender, EventArgs e) {
			new TestForm().Show();
		}

		private void testToolStripMenuItem_Click(object sender, EventArgs e) {
		}

		private void jiToolStripMenuItem_Click(object sender, EventArgs e) {
			new SkillListForm().Show();
		}
	}

	public class FileHeader : IComparable<FileHeader> {
		public string fileName;	// 占256字节，ASCII文本，CodePage=949
		public Int32 packedSize;
		public Int32 realSize;
		public Int32 sizeInPak;
		public Int32 pakOffset;
		public Int32 flag;
		public byte[] reserved; // 40 bytes;
		public string pakFilePath;

		public int CompareTo(FileHeader other) {
			return fileName.CompareTo(other.fileName);
		}
	}

	public class UIString {
		public int id;
		public string text;
	}
}
